home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / LinAlg 3.1 / LinAlg / LinAlg.h < prev    next >
Encoding:
Text File  |  1995-12-20  |  23.8 KB  |  740 lines  |  [TEXT/ALFA]

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *              Linear Algebra Package
  6.  *
  7.  * The present package implements all the basic algorithms dealing
  8.  * with vectors, matrices, matrix columns, etc.
  9.  * Matrix is a basic object in the package; vectors, symmetric matrices,
  10.  * etc. are considered matrices of a special type.
  11.  *
  12.  * Matrix elements are arranged in memory in a COLUMN-wise
  13.  * fashion (in FORTRAN's spirit). In fact, it makes it very easy to
  14.  * feed the matrices to FORTRAN procedures, which implement more
  15.  * elaborate algorithms.
  16.  *
  17.  * Unless otherwise specified, matrix and vector indices always start
  18.  * with 1, spanning up to the specified limit.
  19.  *
  20.  * The present package provides all facilities to completely AVOID returning
  21.  * matrices. Use "Matrix A(Matrix::Transposed,B);" and other fancy constructors
  22.  * as much as possible. If one really needs to return a matrix, return
  23.  * a LazyMatrix object instead. The conversion is completely transparent
  24.  * to the end user, e.g. "Matrix m = haar_matrix(5);" and _is_ efficient.
  25.  *
  26.  * $Id: LinAlg.h,v 3.1 1995/02/03 15:26:10 oleg Exp oleg $
  27.  *
  28.  ************************************************************************
  29.  */
  30.  
  31. #ifndef __GNUC__
  32. #pragma once
  33. #endif
  34. #ifndef _LinAlg_h
  35. #define _LinAlg_h 1
  36.  
  37. #ifdef __GNUC__
  38. #pragma interface
  39. #endif
  40.  
  41. #include "myenv.h"
  42. #include "std.h"
  43. #include <math.h>
  44. #include "builtin.h"
  45. #include <minmax.h>
  46.  
  47. typedef float REAL;            // Scalar field of the Linear Vector
  48.                     // space
  49.  
  50. class Vector;                // Vector over the real domain
  51.  
  52. class MatrixRow;            // A row of the matrix
  53. class MatrixColumn;            // A column of the matrix
  54. class MatrixDiag;            // The diagonal of the matrix
  55. class MatrixPivoting;            // For the determinant evaluation
  56.  
  57.                 // A class to do a specific operation on 
  58.                 // every matrix element regardless of its
  59.                 // position
  60. class ElementPrimAction
  61. {
  62.   friend class Matrix;
  63.   friend class Vector;
  64.   virtual void operation(REAL& element) = 0;
  65.                 // Those are'n implemented; but since they're
  66.                 // private, it forbids the assignement
  67. //  ElementPrimAction(const PixelPrimAction&);
  68.   ElementPrimAction& operator= (const ElementPrimAction&);
  69. };
  70.  
  71.                 // A class to do a specific operation on 
  72.                 // every matrix element as the matrix
  73.                 // is efficiently traversed
  74. class ElementAction
  75. {
  76.   friend class Matrix;
  77.   friend class Vector;
  78.   virtual void operation(REAL& element) = 0;
  79. protected:
  80.   int i, j;            // position of the element being passed to
  81.                 // 'operator()'
  82.  
  83. private:            // Those are'n implemented; but since they're
  84.                 // private, it forbids the assignement
  85. //  ElementAction(const PixelAction&);
  86.   ElementAction& operator= (const ElementAction&);
  87. };
  88.  
  89.                 // Lazy matrix constructor
  90.                 // That is, a promise of a matrix rather than
  91.                 // a matrix itself. The promise is forced
  92.                 // by a Matrix constructor or assignment
  93.                 // operator, see below.
  94.                 // It's highly recommended a function never
  95.                 // return Matrix itself. Use LazyMatrix
  96.                 // instead
  97. class LazyMatrix
  98. {
  99.   friend class Matrix;
  100.   virtual void fill_in(Matrix& m) const = 0;
  101.  
  102.   LazyMatrix(const LazyMatrix&);    // Don't implement to forbid assignment
  103.   LazyMatrix& operator = (const LazyMatrix&);
  104. protected:
  105.   int row_upb, row_lwb, col_upb, col_lwb;
  106. public:
  107.   LazyMatrix(const int nrows, const int ncols)    // Indices start with 1
  108.     : row_upb(nrows), row_lwb(1), col_upb(ncols), col_lwb(1) {}
  109.   LazyMatrix(const int _row_lwb, const int _row_upb,// Or with low:upper
  110.          const int _col_lwb, const int _col_upb)// boundary specif.
  111.     : row_upb(_row_upb), row_lwb(_row_lwb),
  112.       col_upb(_col_upb), col_lwb(_col_lwb) {}
  113. };
  114.  
  115. class MinMax
  116. {
  117.   REAL min_val, max_val;
  118. public:
  119.   MinMax(REAL _min_val, REAL _max_val)
  120.     : min_val(_min_val), max_val(_max_val) {}
  121.   REAL min(void) const        { return min_val; }
  122.   REAL max(void) const        { return max_val; }
  123.   double ratio(void) const    { return max_val/min_val; }
  124. };
  125.  
  126. /*
  127.  *------------------------------------------------------------------------
  128.  *            Basic class of matrix
  129.  */
  130.  
  131. class Matrix            // General type matrix
  132. {
  133.   friend class Vector;
  134.   friend class MatrixRow;
  135.   friend class MatrixColumn;
  136.   friend class MatrixDiag;
  137.   friend class MatrixPivoting;
  138.  
  139. private:            // Private part
  140.   int valid_code;            // Validation code
  141.   enum { MATRIX_val_code = 575767 };    // Matrix validation code value
  142.  
  143. protected:            // May be used in derived classes
  144.   int nrows;                // No. of rows
  145.   int ncols;                // No. of columns
  146.   int row_lwb;                // Lower bound of the row index
  147.   int col_lwb;                // Lower bound of the col index
  148.   char * name;                // Name for the matrix
  149.   int nelems;                // Total no of elements, nrows*ncols
  150.   REAL ** index;            // index[i] = &matrix(0,i) (col index)
  151.   REAL * elements;            // Elements themselves
  152.  
  153.   void allocate(const int nrows, const int ncols,
  154.             const int row_lwb = 1, const int col_lwb = 1);
  155.  
  156.                 // Elementary constructors
  157.   void _transpose(const Matrix& m);    // Allocate new matrix and set it to m'
  158.   void _invert(const Matrix& m);    // Allocate new matrix and set it to minv
  159.   void _AmultB(const Matrix& A, const Matrix& B);    // Matrix multipli-
  160.   void _AtmultB(const Matrix& A, const Matrix& B);    // cators
  161.  
  162.   friend void _make_haar_matrix(Matrix& m);
  163.  
  164. public:            // Public interface
  165.  
  166.                 // Constructors and destructors
  167.                     // Make a blank matrix
  168.   Matrix(const int nrows, const int ncols);    // Indices start with 1
  169.   Matrix(const int row_lwb, const int row_upb,    // Or with low:upper
  170.      const int col_lwb, const int col_upb);    // boundary specif.
  171.  
  172.   Matrix(const Matrix&  another);    // A real copy constructor, expensive
  173.  
  174.                     // Construct a matrix applying a spec
  175.                     // operation to the prototype
  176.                     // Example: Matrix A(10,12);
  177.                     // Matrix B(Matrix::Transposed,A);
  178.   enum MATRIX_CREATORS_1op { Zero, Unit, Transposed, Inverted };
  179.   Matrix(const MATRIX_CREATORS_1op op, const Matrix& prototype);
  180.  
  181.                     // Construct a matrix applying a spec
  182.                     // operation to two prototypes
  183.                     // Example: Matrix A(10,12), B(12,5);
  184.                     // Matrix C(A,Matrix::Mult,B);
  185.   enum MATRIX_CREATORS_2op { Mult,         // A*B
  186.                  TransposeMult,     // A'*B
  187.                  InvMult,         // A^(-1)*B
  188.                  AtBA };         // A'*B*A
  189.   Matrix(const Matrix& A, const MATRIX_CREATORS_2op op, const Matrix& B);
  190.   Matrix(const Vector& x, const Vector& y);    // x'*y (diad) matrix
  191.                     // Construct a matrix applying an
  192.                     // arbitrary action to the prototype
  193. //  Matrix(ElementAction& action, const Matrix& prototype);
  194.   Matrix(const LazyMatrix& lazy_constructor);//Make a matrix using given recipe
  195.   Matrix(const char * file_name);    // Read the matrix from the file
  196.                     // (not yet implemented!)
  197.  
  198.   virtual ~Matrix();            // Destructor
  199.  
  200.   void set_name(const char * name);    // Set a new matrix name
  201.  
  202.                     // Erase the old matrix and create a
  203.                     // new one according to new boundaries
  204.   void resize_to(const int nrows, const int ncols);    // Indexation @ 1
  205.   void resize_to(const int row_lwb, const int row_upb,    // Or with low:upper
  206.          const int col_lwb, const int col_upb);    // boundary specif.
  207.   void resize_to(const Matrix& m);            // Like other matrix m
  208.  
  209.  
  210.   void is_valid() const
  211.   { assure(valid_code == MATRIX_val_code,"Invalid matrix"); }
  212.  
  213.                 // Status inquires
  214.   int q_row_lwb() const            { return row_lwb; }
  215.   int q_row_upb() const            { return nrows+row_lwb-1; }
  216.   int q_nrows()    const            { return nrows; }
  217.   int q_col_lwb() const            { return col_lwb; }
  218.   int q_col_upb() const            { return ncols+col_lwb-1; }
  219.   int q_ncols()    const            { return ncols; }
  220.  
  221.   int q_no_elems() const        { return nelems; }
  222.  
  223.   const char * q_name() const        { return name; }
  224.  
  225.                 // Individual element manipulations
  226.   inline const REAL& operator () (const int rown, const int coln) const;
  227.   REAL& operator () (const int rown, const int coln)
  228.     { return (REAL&)((*(const Matrix *)this)(rown,coln)); }
  229.  
  230.  
  231.             // Element-wise matrix operations
  232.  
  233.                 // Matrix-scalar arithmetics
  234.                 // Modify every element of the
  235.                 // Matrix according to the operation
  236.   Matrix& operator =   (const REAL val);    // Assignment to all the elems
  237.   Matrix& operator -=  (const double val);    // Add to elements
  238.   Matrix& operator +=  (const double val);    // Take from elements
  239.   Matrix& operator *=  (const double val);    // Multiply elements by a val
  240.  
  241.                 // Comparisons
  242.                 // Find out if the predicate
  243.                 // "element op val" is true for ALL matrix
  244.                 // elements
  245.   bool      operator ==  (const REAL val) const;    // ? all elems == val
  246.   bool      operator !=  (const REAL val) const;    // ? all elems != val
  247.   bool      operator <   (const REAL val) const;    // ? all elems <  val
  248.   bool      operator <=  (const REAL val) const;    // ? all elems <= val
  249.   bool      operator >   (const REAL val) const;    // ? all elems >  val
  250.   bool      operator >=  (const REAL val) const;    // ? all elems >= val
  251.  
  252.                 // Other element-wise matrix operations
  253.   Matrix& clear(void);            // Clear the matrix (fill out with 0)
  254.   Matrix& abs(void);            // Take an absolute value of a matrix
  255.   Matrix& sqr(void);            // Square each element
  256.   Matrix& sqrt(void);            // Take a square root
  257.  
  258.   Matrix& apply(ElementPrimAction& action);    // Apply a user-defined action
  259.   Matrix& apply(ElementAction& action);        // to each matrix element
  260.  
  261.                     // Invert the matrix returning the
  262.                     // determinant if desired
  263.                     // determinant = 0 if the matrix is
  264.                     // singular
  265.                     // If determ_ptr=0 and the matrix *is*
  266.                     // singular, throw up
  267.   Matrix& invert(double * determ_ptr = 0);
  268.  
  269.                 // Element-wise operations on two matrices
  270.   inline Matrix& operator = (const Matrix& source);    // Assignment
  271.   Matrix& operator = (const LazyMatrix& source);// Force the promise of a matrix
  272.  
  273.                     // Arithmetics
  274.   friend Matrix& operator += (Matrix& target, const Matrix& source);
  275.   friend Matrix& operator -= (Matrix& target, const Matrix& source);
  276.   friend Matrix& add(Matrix& target, const double scalar,const Matrix& source);
  277.   friend Matrix& element_mult(Matrix& target, const Matrix& source);
  278.   friend Matrix& element_div(Matrix& target, const Matrix& source);
  279.  
  280.                     // Comparisons
  281.   friend bool  operator == (const Matrix& im1, const Matrix& im2);
  282.   friend void compare(const Matrix& im1, const Matrix& im2, 
  283.               const char * title);
  284.   friend inline void are_compatible(const Matrix& im1, const Matrix& im2);
  285.  
  286.  
  287.                 // True matrix operations
  288.                 // (on a matrix as a whole)  
  289.   Matrix& operator *= (const Matrix& source);    // Inplace multiplication
  290.                         // possible only for square src
  291.  
  292.   Matrix& operator *= (const MatrixDiag& diag);    // Multiply by the diagonal of
  293.                         // another matrix
  294.   
  295.   void mult(const Matrix& A, const Matrix& B);  // Compute A*B
  296.  
  297.                 // Compute matrix norms
  298.   double row_norm(void) const;        // MAX{ SUM{ |M(i,j)|, over j}, over i}
  299.   double norm_inf(void) const        // Alias, shows the norm is induced
  300.          { return row_norm(); }        //     by the vector inf-norm
  301.   double col_norm(void) const;        // MAX{ SUM{ |M(i,j)|, over i}, over j}
  302.   double norm_1(void) const        // Alias, shows the norm is induced
  303.          { return col_norm(); }        //     by the vector 1-norm
  304.   double e2_norm(void) const;        // SUM{ m(i,j)^2 }, Note it's square
  305.                     // of the Frobenius rather than 2. norm
  306.  
  307.   friend double e2_norm(const Matrix& m1, const Matrix& m2);
  308.                     // e2_norm(m1-m2)
  309.  
  310.   double determinant(void) const;    // Matrix must be a square one
  311.  
  312.   double asymmetry_index(void) const;    // How far is the matrix from being
  313.                     // symmetrical (0 means complete symm)
  314.                     // (not yet implemented)
  315.  
  316.                 // Make matrices of a special kind
  317.   Matrix& unit_matrix(void);        // Matrix needn't be a square
  318.   Matrix& hilbert_matrix(void);        // Hilb[i,j] = 1/(i+j-1); i,j=1..max
  319.  
  320.                 // I/O: write, read, print 
  321.                       // Write to a file
  322.                     // "| command name" is OK as a file
  323.                     // name
  324.   void write(const char * file_name,const char * title = "") const;
  325.   void info(void) const;        // Print the info about the Matrix
  326.   void print(const char * title) const;    // Print the Matrix as a table
  327.  
  328. };
  329.  
  330.                 // Create an orthogonal (2^n)*(no_cols) Haar
  331.                 // (sub)matrix, whose columns are Haar
  332.                 // functions
  333.                 // If no_cols is 0, create the complete matrix
  334.                 // with 2^n columns
  335. class haar_matrix : public LazyMatrix
  336. {
  337.   void fill_in(Matrix& m) const        { _make_haar_matrix(m); }
  338. public:
  339.   haar_matrix(const int n, const int no_cols=0);
  340. };
  341.  
  342.  
  343. /*
  344.  *------------------------------------------------------------------------
  345.  *            Inline Matrix operations
  346.  */
  347.  
  348. inline Matrix::Matrix(const int no_rows, const int no_cols)
  349. {
  350.   allocate(no_rows,no_cols);
  351. }
  352.  
  353. inline Matrix::Matrix(const int row_lwb, const int row_upb,
  354.               const int col_lwb, const int col_upb)
  355. {
  356.   allocate(row_upb-row_lwb+1,col_upb-col_lwb+1,row_lwb,col_lwb);
  357. }
  358.  
  359. inline Matrix::Matrix(const LazyMatrix& lazy_constructor)
  360. {
  361.   allocate(lazy_constructor.row_upb-lazy_constructor.row_lwb+1,
  362.        lazy_constructor.col_upb-lazy_constructor.col_lwb+1,
  363.        lazy_constructor.row_lwb,lazy_constructor.col_lwb);
  364.   lazy_constructor.fill_in(*this);
  365. }
  366.  
  367.  
  368.                 // Force the promise of a matrix
  369.                 // That is, apply a lazy_constructor
  370.                 // to the current matrix
  371. inline Matrix& Matrix::operator = (const LazyMatrix& lazy_constructor)
  372. {
  373.   is_valid();
  374.   if( lazy_constructor.row_upb != q_row_upb() ||
  375.       lazy_constructor.col_upb != q_col_upb() ||
  376.       lazy_constructor.row_lwb != q_row_lwb() ||
  377.       lazy_constructor.col_lwb != q_col_lwb() )
  378.     info(),
  379.     _error("The matrix above is incompatible with the assigned "
  380.            "Lazy matrix");
  381.       
  382.   lazy_constructor.fill_in(*this);
  383.   return *this;
  384. }
  385.  
  386.                     // Copy constructor, expensive: use
  387.                     // sparingly
  388. inline Matrix::Matrix(const Matrix& another)
  389. {
  390.   another.is_valid();
  391.   allocate(another.nrows,another.ncols,another.row_lwb,another.col_lwb);
  392.   *this = another;
  393. }
  394.  
  395.                 // Resize the matrix to accomodate to a pattern
  396. inline void Matrix::resize_to(const Matrix& m)
  397. {
  398.   resize_to(m.q_row_lwb(),m.q_row_upb(),m.q_col_lwb(),m.q_col_upb());
  399. }
  400.  
  401. inline const REAL& Matrix::operator () (const int rown, const int coln) const
  402. {
  403.   is_valid();
  404.   register int arown = rown-row_lwb;        // Effective indices
  405.   register int acoln = coln-col_lwb;
  406.  
  407.   if( arown >= nrows || arown < 0 )
  408.     _error("Row index %d is out of Matrix boundaries [%d,%d]",
  409.        rown,row_lwb,nrows+row_lwb-1);
  410.   if( acoln >= ncols || acoln < 0 )
  411.     _error("Col index %d is out of Matrix boundaries [%d,%d]",
  412.        coln,col_lwb,ncols+col_lwb-1);
  413.   
  414.   return (index[acoln])[arown];
  415. }
  416.  
  417. inline Matrix& Matrix::clear(void)    // Clean the Matrix
  418. {
  419.   is_valid();
  420.   memset(elements,0,nelems*sizeof(REAL));
  421.   return *this;
  422. }
  423.  
  424. inline void are_compatible(const Matrix& im1, const Matrix& im2)
  425. {
  426.   im1.is_valid();
  427.   im2.is_valid();
  428.   
  429.   if( im1.nrows != im2.nrows || im1.ncols != im2.ncols ||
  430.       im1.row_lwb != im2.row_lwb || im1.col_lwb != im2.col_lwb )
  431.     im1.info(), im2.info(), _error("The matrices above are incompatible");
  432. }
  433.  
  434.                 // Assignment
  435. inline Matrix& Matrix::operator = (const Matrix& source)
  436. {
  437.   are_compatible(*this,source);
  438.   memcpy(elements,source.elements,nelems*sizeof(REAL));
  439.   return *this;
  440. }
  441.  
  442.                 // Apply a user-defined action to each matrix
  443.                 // element
  444. inline Matrix& Matrix::apply(ElementPrimAction& action)
  445. {
  446.   is_valid();
  447.   for(register REAL * ep=elements; ep < elements+nelems; ep++)
  448.     action.operation(*ep);
  449.  
  450.   return *this;
  451. }
  452.  
  453. /*
  454.  *------------------------------------------------------------------------
  455.  *        Friend classes - MatrixRow, MatrixCol, MatrixDiag
  456.  */
  457.  
  458. class MatrixColumn        // Special representation of a Col of the
  459. {                // matrix
  460.   friend class Matrix;
  461.   friend class Vector;
  462.  
  463.   const Matrix& matrix;            // The matrix i am a column of
  464.   REAL * ptr;                // Pointer to the a[0,i]
  465.  
  466. public:                    // Take a col of the matrix
  467.   MatrixColumn(const Matrix& matrix, const int col);
  468.  
  469.                     // Assign a value to all the elements
  470.                     // of the Matrix Col
  471.   void operator = (const REAL val);
  472.                       // Modify the elements in the col
  473.   void operator +=  (const double val);
  474.   void operator *=  (const double val);
  475.  
  476.   void operator = (const Vector& vec);    // Assign a vector to a matrix col
  477.  
  478.                       // Individual element manipulations
  479.   inline const REAL& operator () (const int i) const;
  480.   inline REAL& operator () (const int i)
  481.     { return (REAL&)((*(const MatrixColumn *)this)(i)); }
  482. };
  483.  
  484.                 // Construct the MatrixColumn
  485. inline MatrixColumn::MatrixColumn(const Matrix& _matrix, const int col)
  486.     : matrix(_matrix)
  487. {
  488.   matrix.is_valid();
  489.  
  490.   register int colind = col - matrix.col_lwb;
  491.  
  492.   if( colind >= matrix.ncols || colind < 0 )
  493.     matrix.info(),
  494.     _error("Column #%d is not within the above matrix",col);
  495.  
  496.   MatrixColumn::ptr = &(matrix.index[colind][0]);
  497. }
  498.  
  499.                 // Access the i-th element of the column
  500. inline const REAL& MatrixColumn::operator () (const int i) const
  501. {
  502.   matrix.is_valid();
  503.   register int arown = i-matrix.row_lwb;        // Effective indices
  504.  
  505.   if( arown >= matrix.nrows || arown < 0 )
  506.     _error("MatrixColumn index %d is out of column boundaries [%d,%d]",
  507.        i,matrix.row_lwb,matrix.nrows+matrix.row_lwb-1);
  508.   return ptr[arown];
  509. }
  510.  
  511. class MatrixRow            // Special representation of a Row of the
  512. {                // matrix
  513.   friend class Matrix;
  514.   friend class Vector;
  515.  
  516.   const Matrix& matrix;            // The matrix i am a row of
  517.   const int inc;            // if ptr=@a[row,i], then
  518.                     //    ptr+inc = @a[row,i+1]
  519.                     // Since elements of a[] are stored
  520.                     // col after col, inc = nrows
  521.   REAL * ptr;                // Pointer to the a[row,0]
  522.  
  523. public:                // Take a row of the matrix
  524.   MatrixRow(const Matrix& matrix, const int row);
  525.  
  526.                     // Assign a value to all the elements
  527.                     // of the Matrix Row   
  528.   void operator = (const REAL val);
  529.                       // Modify the elements in the row
  530.   void operator +=  (const double val);
  531.   void operator *=  (const double val);
  532.  
  533.   void operator = (const Vector& vec);    // Assign a vector to a matrix row
  534.  
  535.                       // Individual element manipulations
  536.   inline const REAL& operator () (const int i) const;
  537.   inline REAL& operator () (const int i)
  538.     { return (REAL&)((*(const MatrixRow *)this)(i)); }
  539. };
  540.  
  541.                 // Construct the MatrixRow
  542. inline MatrixRow::MatrixRow(const Matrix& _matrix, const int row)
  543.   : matrix(_matrix), inc(_matrix.nrows)
  544. {
  545.   matrix.is_valid();
  546.  
  547.   register int rowind = row - matrix.row_lwb;
  548.  
  549.   if( rowind >= matrix.nrows || rowind < 0 )
  550.     matrix.info(),
  551.     _error("Row #%d is not within the above matrix",row);
  552.  
  553.   MatrixRow::ptr = &(matrix.index[0][rowind]);
  554. }
  555.  
  556.                 // Get hold of the i-th row's element
  557. inline const REAL& MatrixRow::operator () (const int i) const
  558. {
  559.   matrix.is_valid();
  560.   register int acoln = i-matrix.col_lwb;        // Effective index
  561.  
  562.   if( acoln >= matrix.ncols || acoln < 0 )
  563.     _error("MatrixRow index %d is out of row boundaries [%d,%d]",
  564.        i,matrix.col_lwb,matrix.ncols+matrix.col_lwb-1);
  565.   return matrix.index[acoln][ptr-matrix.elements];
  566. }
  567.  
  568.  
  569.  
  570. class MatrixDiag        // Special representation of the diagonal of a
  571. {                // matrix (for easy manipulation)
  572.   friend class Matrix;
  573.   friend class Vector;
  574.  
  575.   const Matrix& matrix;            // The matrix i am the diagonal of
  576.   const int inc;            // if ptr=@a[i,i], then
  577.                     //    ptr+inc = @a[i+1,i+1]
  578.                     // Since elements of a[] are stored
  579.                     // col after col, inc = nrows+1
  580.   const int ndiag;            // No of diag elems, min(nrows,ncols)
  581.   REAL * ptr;                // Pointer to the a[0,0]
  582.  
  583. public:                    // Take a diag of the matrix
  584.   MatrixDiag(const Matrix& matrix);
  585.                     // Assign a value to all the elements
  586.                     // of the Matrix Diag
  587.   void operator = (const REAL val);
  588.                       // Modify the elements in the diag
  589.   void operator +=  (const double val);
  590.   void operator *=  (const double val);
  591.  
  592.   void operator = (const Vector & vec);    // Assign a vector to a matrix diag
  593.  
  594.                       // Individual element manipulations
  595.   inline const REAL& operator () (const int i) const;
  596.   inline REAL& operator () (const int i)
  597.     { return (REAL&)((*(const MatrixDiag *)this)(i)); }
  598.   int q_ndiags(void) const        { return ndiag; }
  599. };
  600.  
  601.                 // Construct the MatrixDiag
  602. inline MatrixDiag::MatrixDiag(const Matrix& _matrix)
  603. : matrix(_matrix), inc(_matrix.nrows+1), 
  604.   ndiag(::min(_matrix.nrows,_matrix.ncols))
  605. {
  606.   matrix.is_valid();
  607.   MatrixDiag::ptr = &(matrix.elements[0]);
  608. }
  609.  
  610.                 // Get hold of the i-th diag element
  611.                 // (indexing always starts at 1, regardless
  612.                 // of matrix' col_lwb and row_lwb)
  613. inline const REAL& MatrixDiag::operator () (const int i) const
  614. {
  615.   matrix.is_valid();
  616.   if( i > ndiag || i < 1 )
  617.     _error("MatrixDiag index %d is out of diag boundaries [1,%d]",
  618.        i,ndiag);
  619.   return matrix.index[i-1][i-1];
  620. }
  621.  
  622. /*
  623.  *------------------------------------------------------------------------
  624.  *           Vector as a n*1 matrix (that is, a col-matrix)
  625.  */
  626.  
  627. class Vector : public Matrix
  628. {
  629.   friend class MatrixRow;
  630.   friend class MatrixColumn;
  631.   friend class MatrixDiag;
  632.  
  633. public:
  634.   Vector(const int n);        // Specify a blank vector for a given
  635.                     // dimension, with indexation at 1
  636.   Vector(const int lwb, const int upb); // Specify a general lwb:upb vector
  637. //  Vector(const Vector& another);    // a copy constructor (to be inferred)
  638.  
  639.                     // Make a vector and assign init vals
  640.   Vector(const int lwb, const int upb,  // lower and upper bounds
  641.      double iv1, ...            // DOUBLE numbers. The last arg of
  642.      );                 // the list must be string "END"
  643.                     // E.g: Vector f(1,2,0.0,1.5,"END");
  644.  
  645.   Vector(const LazyMatrix& lazy_constructor);//Make a vector using given recipe
  646.  
  647.                 // Resize the vector (keeping as many old
  648.                 // elements as possible), expand by zeros
  649.   void resize_to(const int n);            // Indexation @ 1
  650.   void resize_to(const int lwb, const int upb);     // lwb:upb specif
  651.   void resize_to(const Vector& v);            // like other vector
  652.  
  653.   inline REAL & operator () (const int index) const;
  654.   inline REAL& operator () (const int index)
  655.     { return (REAL&)((*(const Vector *)this)(index)); }
  656.  
  657.                 // Listed below are specific vector operations
  658.                 // (unlike n*1 matrices)
  659.  
  660.                     // Status inquires
  661.   int q_lwb(void) const        { return row_lwb; }
  662.   int q_upb(void) const        { return nrows + row_lwb - 1; }
  663.  
  664.                     // Compute the scalar product
  665.   friend double operator * (const Vector& v1, const Vector& v2);
  666.  
  667.                     // "Inplace" multiplication
  668.                     // target = A*target
  669.                     // A needn't be a square one (the
  670.                     // target will be resized to fit)
  671.   Vector& operator *= (const Matrix& A);
  672.  
  673.   Vector& operator *=  (const double val)    // Multiply elements by a val
  674.     { Matrix::operator *=(val); return *this; }
  675.  
  676.                     // Vector norms
  677.   double norm_1(void) const;               // SUM{ |v[i]| }
  678.   double norm_2_sqr(void) const;               // SUM{ v[i]^2 }
  679.   double norm_inf(void) const;            // MAX{ |v[i]| }
  680.  
  681.   Vector& operator = (const Vector& v)
  682.       { Matrix::operator =(v); return *this; }
  683.   Vector& operator = (const REAL val)    // Assign to all elems of a vector
  684.       { Matrix::operator =(val); return *this; }
  685.   Vector& operator = (const LazyMatrix& source)// Force the promise of a vector
  686.       { Matrix::operator =(source); return *this; }
  687.  
  688.   Vector& operator = (const MatrixRow& mr);
  689.   Vector& operator = (const MatrixColumn& mc);
  690.   Vector& operator = (const MatrixDiag& md);
  691. };
  692.   
  693.                 // Create a blank vector of a given size
  694. inline Vector::Vector(const int n) : Matrix(n,1)
  695. {}
  696.  
  697.                 // Create a general blank vector
  698. inline Vector::Vector(const int lwb, const int upb) : Matrix(lwb,upb,1,1)
  699. {}
  700.  
  701.                 // Resize the vector for a specified number
  702.                 // of elements, trying to keep intact as many
  703.                 // elements of the old vector as possible.
  704.                 // If the vector is expanded, the new elements
  705.                 // will be zeroes
  706. inline void Vector::resize_to(const int n)    { Vector::resize_to(1,n); }
  707.  
  708. inline void Vector::resize_to(const Vector& v)
  709. {
  710.   Vector::resize_to(v.q_lwb(),v.q_upb());
  711. }
  712.  
  713.                 // Get access to a vector element
  714. inline REAL& Vector::operator () (const int ind) const
  715. {
  716.   is_valid();
  717.   register int aind = ind - row_lwb;
  718.   if( aind >= nelems || aind < 0 )
  719.     _error("Requested element %d is out of Vector boundaries [%d,%d]",
  720.        ind,row_lwb,nrows+row_lwb-1);
  721.   
  722.   return elements[aind];
  723. }
  724.  
  725.                 // Make a vector follow a recipe
  726. inline Vector::Vector(const LazyMatrix& lazy_constructor)
  727.   : Matrix(lazy_constructor)
  728. {
  729.   assure(ncols == 1 && col_lwb == 1,
  730.          "cannot make a vector from a promise of a full matrix");
  731. }
  732.  
  733.                 // Service functions (useful in the
  734.                 // verification code). They print some detail
  735.                 // info if the validation condition fails
  736. void verify_element_value(const Matrix& m,const REAL val);
  737. void verify_matrix_identity(const Matrix& m1, const Matrix& m2);
  738.  
  739. #endif
  740.